package pub.devrel.easypermissions;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.aafwk.content.Intent;
import ohos.agp.window.dialog.CommonDialog;
import ohos.agp.window.dialog.IDialog;
import ohos.app.AbilityContext;
import ohos.utils.Parcel;
import ohos.utils.Sequenceable;

/**
 * Dialog to prompt the user to go to the app's settings screen and enable permissions. If the user
 * clicks 'OK' on the dialog, they are sent to the settings screen. The result is returned to the
 * Ability via {@see Ability#onAbilityResult(int, int, Intent)}.
 * <p>
 * Use the {@link Builder} to create and display a dialog.
 */
public class AppSettingsDialog implements Sequenceable {
    private static final String TAG = "EasyPermissions";

    public static final int DEFAULT_SETTINGS_REQ_CODE = 16061;
    public static final Producer<AppSettingsDialog> PRODUCER = new Producer<AppSettingsDialog>() {
        public AppSettingsDialog createFromParcel(Parcel in) {
            // Initialize an instance first, then do customized unmarshlling.
            AppSettingsDialog instance = new AppSettingsDialog(in);
            instance.unmarshalling(in);
            return instance;
        }
    };
    static final String EXTRA_APP_SETTINGS = "extra_app_settings";
    private final int mThemeResId;
    private final String mRationale;
    private final String mTitle;
    private final String mPositiveButtonText;
    private final String mNegativeButtonText;
    private final int mRequestCode;
    private final int mIntentFlags;

    private Object mAbilityOrFragment;
    private AbilityContext mContext;

    private AppSettingsDialog(Parcel in) {
        mThemeResId = in.readInt();
        mRationale = in.readString();
        mTitle = in.readString();
        mPositiveButtonText = in.readString();
        mNegativeButtonText = in.readString();
        mRequestCode = in.readInt();
        mIntentFlags = in.readInt();
    }

    private AppSettingsDialog(final Object abilityOrFragment, int themeResId, String rationale,
                              String title, String positiveButtonText, String negativeButtonText,
                              int requestCode, int intentFlags) {
        setAbilityOrFragment(abilityOrFragment);
        mThemeResId = themeResId;
        mRationale = rationale;
        mTitle = title;
        mPositiveButtonText = positiveButtonText;
        mNegativeButtonText = negativeButtonText;
        mRequestCode = requestCode;
        mIntentFlags = intentFlags;
    }

    static AppSettingsDialog fromIntent(Intent intent, Ability ability) {
//        AppSettingsDialog dialog = intent.getParcelableExtra(AppSettingsDialog.EXTRA_APP_SETTINGS);
        AppSettingsDialog dialog = intent.getSequenceableParam(AppSettingsDialog.EXTRA_APP_SETTINGS);

        // It's not clear how this could happen, but in the case that it does we should try
        // to avoid a runtime crash and just use the default dialog.
        // https://github.com/googlesamples/easypermissions/issues/278
        if (dialog == null) {
            dialog = new Builder(ability).build();
        }

        dialog.setAbilityOrFragment(ability);
        return dialog;
    }

    private void setAbilityOrFragment(Object abilityOrFragment) {
        mAbilityOrFragment = abilityOrFragment;

        if (abilityOrFragment instanceof Ability) {
            mContext = (AbilityContext) abilityOrFragment;
        } else if (abilityOrFragment instanceof Fraction) {
            mContext = (AbilityContext) ((Fraction) abilityOrFragment).getFractionAbility().getContext();
        } else {
            throw new IllegalStateException("Unknown object: " + abilityOrFragment);
        }
    }

    private void startForResult(Intent intent) {
        if (mAbilityOrFragment instanceof Ability) {
            ((Ability) mAbilityOrFragment).startAbilityForResult(intent, mRequestCode);
        } else if (mAbilityOrFragment instanceof Fraction) {
            ((Fraction) mAbilityOrFragment).startAbility(intent, mRequestCode);
        }
    }

    /**
     * Display the built dialog.
     */
    public void show() {
        startForResult(AppSettingsDialogHolderAbility.createShowDialogIntent(mContext, this));
    }

    /**
     * Show the dialog. {@link #show()} is a wrapper to ensure backwards compatibility
     *
     * @param positiveListener 按钮监听
     * @param negativeListener 按钮监听
     * @return CommonDialog dialog对象
     */
    CommonDialog showDialog(IDialog.ClickedListener positiveListener,
                            IDialog.ClickedListener negativeListener) {
        CommonDialog commonDialog = new CommonDialog(mContext);
        commonDialog.show();
        return commonDialog;
    }

    int getIntentFlags() {
        return mIntentFlags;
    }

    @Override
    public boolean marshalling(Parcel parcel) {
        parcel.writeInt(mThemeResId);
        parcel.writeString(mRationale);
        parcel.writeString(mTitle);
        parcel.writeString(mPositiveButtonText);
        parcel.writeString(mNegativeButtonText);
        parcel.writeInt(mRequestCode);
        parcel.writeInt(mIntentFlags);
        return true;
    }

    @Override
    public boolean unmarshalling(Parcel parcel) {
        return true;
    }

    /**
     * Builder for an {@link AppSettingsDialog}.
     */
    public static class Builder {
        private final Object mAbilityOrFragment;
        private final AbilityContext mContext;
        private int mThemeResId = -1;
        private String mRationale;
        private String mTitle;
        private String mPositiveButtonText;
        private String mNegativeButtonText;
        private int mRequestCode = -1;
        private boolean mOpenInNewTask = false;

        /**
         * Create a new Builder for an {@link AppSettingsDialog}.
         *
         * @param ability the {@link Ability} in which to display the dialog.
         */
        public Builder(Ability ability) {
            mAbilityOrFragment = ability;
            mContext = ability;
        }

        /**
         * Create a new Builder for an {@link AppSettingsDialog}.
         *
         * @param fragment the {@link Fraction} in which to display the dialog.
         */
        public Builder(Fraction fragment) {
            mAbilityOrFragment = fragment;
            mContext = (AbilityContext) fragment.getFractionAbility().getContext();
        }

        /**
         * Set the dialog theme.
         *
         * @param themeResId 主题资源id
         * @return builder
         */
        public Builder setThemeResId(int themeResId) {
            mThemeResId = themeResId;
            return this;
        }

        /**
         * Set the title dialog. Default is "Permissions Required".
         *
         * @param title dialog标题
         * @return builder
         */
        public Builder setTitle(String title) {
            mTitle = title;
            return this;
        }

        /**
         * Set the title dialog. Default is "Permissions Required".
         *
         * @param title dialog标题
         * @return builder
         */
        public Builder setTitle(int title) {
            mTitle = mContext.getString(title);
            return this;
        }

        /**
         * Set the rationale dialog. Default is
         * "This app may not work correctly without the requested permissions.
         * Open the app settings screen to modify app permissions."
         *
         * @param rationale dialog提示内容
         * @return builder
         */
        public Builder setRationale(String rationale) {
            mRationale = rationale;
            return this;
        }

        /**
         * Set the rationale dialog. Default is
         * "This app may not work correctly without the requested permissions.
         * Open the app settings screen to modify app permissions."
         *
         * @param rationale 设置dialog内容
         * @return builder
         */
        public Builder setRationale(int rationale) {
            mRationale = mContext.getString(rationale);
            return this;
        }

        /**
         * Set the positive button text, default is {@link }.
         *
         * @param text 按钮上的文字
         * @return builder
         */
        public Builder setPositiveButton(String text) {
            mPositiveButtonText = text;
            return this;
        }

        /**
         * Set the positive button text, default is {@link }.
         *
         * @param textId 资源id
         * @return builder
         */
        public Builder setPositiveButton(int textId) {
            mPositiveButtonText = mContext.getString(textId);
            return this;
        }

        /**
         * Set the negative button text, default is {@link }.
         * <p>
         * To know if a user cancelled the request, check if your permissions were given with {@link
         * EasyPermissions#} in {@see
         * Ability#onAbilityResult(int, int, Intent)}. If you still don't have the right
         * permissions, then the request was cancelled.
         *
         * @param text 按钮上的文字
         * @return builder
         */
        public Builder setNegativeButton(String text) {
            mNegativeButtonText = text;
            return this;
        }

        /**
         * Set the negative button text, default is {@link }.
         *
         * @param textId 控件id
         * @return builder
         */
        public Builder setNegativeButton(int textId) {
            mNegativeButtonText = mContext.getString(textId);
            return this;
        }

        /**
         * Set the request code use when launching the Settings screen for result, can be retrieved
         * in the calling Ability's {@see Ability#onAbilityResult(int, int, Intent)} method.
         * Default is {@link #DEFAULT_SETTINGS_REQ_CODE}.
         *
         * @param requestCode 请求code
         * @return builder
         */
        public Builder setRequestCode(int requestCode) {
            mRequestCode = requestCode;
            return this;
        }

        /**
         * Set whether the settings screen should be opened in a separate task. This is achieved by
         * setting {@link} on
         * the Intent used to open the settings screen.
         *
         * @param openInNewTask 是否是新的task
         * @return builder
         */
        public Builder setOpenInNewTask(boolean openInNewTask) {
            mOpenInNewTask = openInNewTask;
            return this;
        }

        /**
         * Build the {@link AppSettingsDialog} from the specified options. Generally followed by a
         * call to {@link AppSettingsDialog#show()}.
         *
         * @return 返回Dialog对象
         */
        public AppSettingsDialog build() {
            mRationale = (mRationale == null || mRationale.isEmpty())
                ? mContext.getString(ResourceTable.String_rationale_ask_again) : mRationale;
            mTitle = (mTitle == null || mTitle.isEmpty())
                ? mContext.getString(ResourceTable.String_title_settings_dialog) : mTitle;
            mPositiveButtonText = (mPositiveButtonText == null || mPositiveButtonText.isEmpty())
                ? mContext.getString(ResourceTable.String_ok) : mPositiveButtonText;
            mNegativeButtonText = (mNegativeButtonText == null || mNegativeButtonText.isEmpty())
                ? mContext.getString(ResourceTable.String_cancel) : mNegativeButtonText;
            mRequestCode = mRequestCode > 0 ? mRequestCode : DEFAULT_SETTINGS_REQ_CODE;

            int intentFlags = 0;
            if (mOpenInNewTask) {
            }

            return new AppSettingsDialog(
                mAbilityOrFragment,
                mThemeResId,
                mRationale,
                mTitle,
                mPositiveButtonText,
                mNegativeButtonText,
                mRequestCode,
                intentFlags);
        }
    }
}
